# -*- coding: utf-8 -*-
#
# Messenger Plus Sound EN
# The Messenger Plus Sound plugin, enable the reception of sounds sent
# by the WLM mod : Live Messenger Plus (old MSN+). If you want it work fine
# It need : play and wget installed.
# Thanks a lot for the help of the emesene forum and particulary of JoinTheHell and C10ud
#
# Giovanni Olivera
#


import os
import gtk
import urllib2
from threading import Thread
from gobject import timeout_add, source_remove

import Plugin

VERSION = '0.4'

class SoundsWindow(gtk.Window):
    '''A window with sounds list'''
    def __init__(self, dbFile, playCallback, sendCallback, \
                                        theme, conversation):

        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        self.set_decorated(False)
        self.set_resizable(False)
        self.set_app_paintable(True)
        self.set_border_width(5)
        self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
        self.set_position(gtk.WIN_POS_MOUSE)

        self.connect('leave-notify-event', self.on_leave_notify_event)
        self.connect('expose-event', self.on_expose_event )

        self.playCallback = playCallback
        self.sendCallback = sendCallback
        self.conversation = conversation

        self.closed = False
        self.tag = None
        self.buttonHover = False

        self.vbox = gtk.VBox()
        self.vbox.pack_start(gtk.Label("Sounds:"), False)
        self.table = gtk.Table()

        try:
            f = open(dbFile, "r")
            r = f.read()
        except:
            print "emesene Plus Sound Exception: "
            print "can't read ", dbFile
            r = ""
        y = 0
        for line in r.splitlines():
            id = line.split("id=")[1].split(" ")[0]
            name = " ".join(line.split("name=")[1:])

            hbox = gtk.HBox()
           
            pixbuf = theme.getSmiley("(8)")
            playImage = gtk.Image()
            if type(pixbuf) == gtk.gdk.PixbufAnimation:
                playImage.set_from_animation(pixbuf)
            else:
                playImage.set_from_pixbuf(pixbuf)

            playButton = gtk.Button()
            playButton.set_relief(gtk.RELIEF_NONE)
            playButton.set_image(playImage)
            playButton.connect("clicked", self.on_play_button_clicked, id, name)
            playButton.connect("enter-notify-event", self.on_button_enter_notify)
            playButton.connect("leave_notify_event", self.on_button_leave_notify)

            sendButton = gtk.Button()
            sendButton.set_image(gtk.image_new_from_stock(gtk.STOCK_GOTO_TOP, \
                                                        gtk.ICON_SIZE_BUTTON))
            sendButton.set_relief(gtk.RELIEF_NONE)
            sendButton.connect("clicked", self.on_send_button_clicked, id, name)
            sendButton.connect("enter-notify-event", self.on_button_enter_notify)
            sendButton.connect("leave_notify_event", self.on_button_leave_notify)

            self.table.attach(gtk.Label(name), 0, 1, y, y +1)
            self.table.attach(playButton, 1, 2, y, y +1)
            self.table.attach(sendButton, 2, 3, y, y +1)

            y += 1
            

        self.vbox.pack_start(self.table, False)

        self.add(self.vbox)
        self.show_all()

    def on_leave_notify_event(self, *args):
        if not self.tag and not self.closed:
            self.tag = timeout_add(500, self.hide)

    def on_button_enter_notify(self, *args):
        self.buttonHover = True
    
    def on_button_leave_notify(self, *args):
        self.buttonHover = False

    def show(self):
        gtk.Window.show(self)
        self.tag = None
        self.closed = False

    def hide(self):
        if not self.buttonHover:
            gtk.Window.hide(self)
            if (self.tag):
                source_remove(self.tag)
                self.tag = None
            self.closed = True

        self.tag = None
        self.closed = False
    
    def on_play_button_clicked(self, widget, id, name):
        self.playCallback(id, name, self.conversation)
        gtk.Window.hide(self)

    def on_send_button_clicked(self, widget, id, name):
        self.sendCallback(id, name, self.conversation)
        gtk.Window.hide(self)

    def on_expose_event( self, window, event):
        width, height = window.get_size()
        window.style.paint_flat_box(window.window, \
                 gtk.STATE_NORMAL, gtk.SHADOW_OUT, \
                           None, window, 'tooltip', \
                                0, 0, width, height)    

class MainClass(Plugin.Plugin):
    '''Main plugin class'''

    def __init__(self, controller, msn):
        '''Contructor'''
        Plugin.Plugin.__init__( self, controller, msn )
        self.description = _('Let you send/receive/play MSN Plus sounds.Last release by DarKprince')
        self.authors = { 'Giovanni Olivera' : 'gino123412@gmail.com', \
                         'j0hn' : 'j0hn.com.ar@gmail.com'}
        self.website = 'http://pofproductions.free.fr/ \nhttp://www.j0hn.com.ar'
        self.displayName = _('MSNPlusSound')
        self.name = 'MSNPlusSound'
	self.enabled = False
        self.controller = controller
        self.Slash = controller.Slash
        self.config = self.controller.config
        self.configPath = os.sep +self.config.getPluginValue(self.name, \
                                              'soundpath', '/msn+sounds')
        self.buttons = {}

    def start(self):
        '''start the plugin'''
        self.config.readPluginConfig(self.name)
        self.configPath = self.config.getPluginValue(self.name, 'soundpath', \
                                                              '/msn+sounds')
        
        self.newMsgId = self.controller.unifiedParser.connect('filter', \
                                                             self.newMsg)
        #self.Slash.register('lssound', self.lssound, 'List all MSN Plus sounds')
        
        self.signalopen = self.controller.conversationManager.connect('new-conversation-ui', self.add_button)
        self.signalclose = self.controller.conversationManager.connect('close-conversation-ui', self.remove_button)

        
        filePath = os.path.expanduser('~') + self.configPath + os.sep
        filePath += "soundlist.db"

        if not os.path.exists(filePath):
            f = open(filePath, "w")
            f.close()

        self.buttons = {}
        for conversation in self.getOpenConversations():
            self.add_button(conversation=conversation)

        self.enabled = True
    
    def stop(self):    
        '''stop the plugin'''
      
        self.controller.unifiedParser.disconnect(self.newMsgId)
        #self.Slash.unregister('lssound')

        self.controller.conversationManager.disconnect(self.signalopen)
        self.controller.conversationManager.disconnect(self.signalclose)

        for conversation in self.buttons.keys():
            conversation.ui.input.toolbar.remove(self.buttons[conversation])
        self.buttons = {}
        self.enabled = False

    def add_button(self, conversationmanager=None, conversation=None, win=None):
        button = gtk.ToolButton(None, '♫')
        button.connect("clicked", self.on_button_clicked)
        button.conversation = conversation
        toolbar = conversation.ui.input.toolbar
        toolbar.add(button)
        button.show()
        toolbar.show_all()
        
        self.buttons[conversation] = button

    def remove_button(self, conversationmanager=None, conversation=None, win=None):
        toolbar = conversation.ui.input.toolbar
        button = self.buttons[conversation]
        self.buttons.pop(conversation)
        toolbar.remove(button)
        

    def on_button_clicked(self, widget):
        filePath = os.path.expanduser('~') + self.configPath
        filePath += os.sep + "soundlist.db"
        window = SoundsWindow(filePath, self.playSound, self.sendSound, \
                               self.controller.theme, widget.conversation)

    def sendSound(self, soundID, name, conversation):
        command = '[Messenger Plus! Sound] - Data{' + soundID + '} - ' + name
        spaces = 104 - len(command)
        conversation.sendMessage(command + " "*spaces)
	
	filePath = os.path.expanduser('~') + os.sep
        filePath += self.configPath + os.sep + soundID + '.mp3'

        os.popen4('play ' + filePath)

    def lssound(self, slashAction):
        try:
            filePath = os.path.expanduser('~') + self.configPath
            filePath += os.sep + "soundlist.db"
            f = open(filePath, "r")
            for line in f.read().splitlines():
                id = line.split("id=")[1].split(" ")[0]
                name = " ".join(line.split("name=")[1:])
                slashAction.outputText(str(name) + " (ID " + str(id) + ")")
        except Exception, e:
            print self.name + " Exception: "
            print e


    def configure(self):
        '''display a configuration dialog'''
        self.confW = Plugin.ConfigWindow(_('Messenger Plus Sounds config'), '')
        lblPath = gtk.Label(_('MSN+ Directory (in ~): '))
        txtPath = gtk.Entry()
        txtPath.set_text(self.configPath)

        self.confW.vbox.pack_start(lblPath)
        self.confW.vbox.pack_start(txtPath)
        self.confW.show_all()
        
        r = self.confW.run()

        if r is not None:
            self.config.setPluginValue( self.name, 'soundpath', txtPath.get_text() )
            
            #yeah, i like this hack :)
            self.stop()
            self.start() 

        return True

    def check(self):
        if os.path.isdir(os.path.expanduser('~') + self.configPath):
            return (True, 'Ok')
        else:
            os.mkdir(os.path.expanduser('~') + self.configPath)
            if os.path.isdir(os.path.expanduser('~') + self.configPath):
                return (True, 'Ok')
            else:
                return (False, 'Error')
            
    def newMsg( self, parser, dataType, filterdata ):
        if not dataType or dataType.getDataType() != 'conversation':
            return
         
        format, objects = filterdata.serialize(filterdata.list)
        if format.count('[Messenger Plus! Sound]') and format.count('Data{'):
            SoundID = format.split("{")[1].split("}")[0]
            SoundName = " ".join(format.split("} - ")[1:])
            MSNPlusSound(SoundID, SoundName, self.configPath, self.playSound).start()
            
        filterdata.list = filterdata.deserialize(format, objects)
    
    def playSound(self, id,name, conversation):
        filePath = os.path.expanduser('~') + os.sep
        filePath += self.configPath + os.sep + id + '.mp3'

        os.popen4('play ' + filePath)
	command = 'Eseguendo ... [Messenger Plus! Sound] - Data{' + id + '} - ' + name
        conversation.appendOutputText(None, command, 'information')

class MSNPlusSound(Thread):
    '''Thread to download the sound and not freeze the GUI'''
    def __init__(self, soundID, soundName, configPath, playsound):
        Thread.__init__(self)
        self.soundID = soundID
        self.soundName = soundName
        self.configPath = configPath
        
        self.filePath = os.path.expanduser('~') + os.sep
        self.filePath += self.configPath + os.sep + self.soundID + '.mp3'
        
        self.playsound = playsound
    
    def run(self):
        if os.path.isfile(self.filePath):
            self.playsound(self, soundID,soundName)
            return
        
        URL1 = 'http://sounds.msgpluslive.net/esnd/snd/check?hash=' + self.soundID
        URL2 = 'http://sounds.msgpluslive.net/esnd/snd/get?hash=' + self.soundID 
        
        req = urllib2.Request(URL1)
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0')
        req.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
        req.add_header('Accept', 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5')
        req.add_header('Accept-Language', 'en,fr;q=0.5')
        o = urllib2.urlopen(req)
        response = o.read()
        
        if response.count('1'):
            soundFile = urllib2.urlopen(URL2)
            soundData = soundFile.read()
            f = open(self.filePath, 'w')
            f.write(soundData)
            f.close()
            self.addSound(self.soundID, self.soundName)
            self.playsound(self, soundID,soundName)
    
    def addSound(self, soundID, name):
        filePath = os.path.expanduser('~') + self.configPath
        filePath += os.sep + "soundlist.db"
        f = open(filePath, "r")
        r = f.read()
        f.close()
        
        for line in r.splitlines():
            if line.count("id=" + soundID):
                return True
        
        try:
            f = open(filePath, "a")
            f.write("id="+ str(soundID) + " " + "name=" + str(name.strip()) + "\n")
            f.close()
        except Exception, e:
            print "emesene Plus Sound Exception: "
            print e
            return False    
            
        
